/* 
 *  javascribd - Java client library for the Scribd API. 
 *  Copyright (C) 2009 by Marcel Eyke, http://code.google.com/p/javascribd/ 
 *  Use is subject to license terms of LGPLv3. See license.txt. 
 */
package com.google.code.javascribd.connection;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.UndeclaredThrowableException;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

import com.google.code.javascribd.connection.jaxbadapter.ApiKeyAdapter;
import com.google.code.javascribd.connection.jaxbadapter.ConversionStatusAdapter;
import com.google.code.javascribd.connection.jaxbadapter.DocumentIdAdapter;
import com.google.code.javascribd.connection.jaxbadapter.SessionKeyAdapter;

public class JaxbResponseParser implements ScribdResponseParser {
	private static final Logger LOG = Logger.getLogger(JaxbResponseParser.class.getName());

	public <T extends ScribdResponse> T parse(InputStream inputStream, Class<T> clazz) throws IOException {
		InputStreamReader reader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
		try {
			return parse(reader, clazz);
		} catch (IOException e) {
			throw e;
		} catch (JAXBException e) {
			/* TODO, May 1, 2009, meyke - own interpret exception */
			throw new UndeclaredThrowableException(e);
		}
	}

	private static <T extends ScribdResponse> T parse(Reader reader, Class<T> clazz) throws JAXBException, IOException {
		try {
			JAXBContext jc = JAXBContext.newInstance(clazz);

			Unmarshaller unmarshaller = jc.createUnmarshaller();
			unmarshaller.setAdapter(new ApiKeyAdapter());
			unmarshaller.setAdapter(new ConversionStatusAdapter());
			unmarshaller.setAdapter(new DocumentIdAdapter());
			unmarshaller.setAdapter(new SessionKeyAdapter());
			if (LOG.isLoggable(Level.FINE)) {
				BufferedReader bufferedReader = new BufferedReader(reader);
				if (bufferedReader.markSupported()) {
					bufferedReader.mark(100000);
					StringBuffer sb = new StringBuffer();
					String line = null;
					do {
						line = bufferedReader.readLine();
						sb.append(line != null ? line + "\n" : "");

					} while (line != null);
					LOG.fine(sb.toString());
					bufferedReader.reset();
				}
				reader = bufferedReader;
			}

			JAXBElement<T> unmarshal = unmarshaller.unmarshal(new StreamSource(reader), clazz);
			return unmarshal.getValue();
		} finally {
			if (reader != null) {
				reader.close();
			}
		}
	}
}
